/*!
 Temelia - Common interface implementation source file.

 Copyright (C) 2008, 2009 Ceata (http://ceata.org/proiecte/temelia).

 @author Dascalu Laurentiu

 This program is free software; you can redistribute it and
 modify it under the terms of the GNU General Public License
 as published by the Free Software Foundation; either version 3
 of the License, or (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

#include "include/common.h"
#include "include/stack.h"
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>

// Common interface implementation.
DECLSPEC int temelia_errno;
static FILE *fout = NULL;

void *_new(int size)
{
	void *memory_allocated;

	if ((memory_allocated = malloc(size)) == NULL)
		temelia_errno = MEMORY_ALLOCATION;

#ifdef VERBOSE
	LOGGER("memory (%p) = malloc (%d)\n", memory_allocated, size);
#endif

	return memory_allocated;
}

void *_realloc(void *old_addr, int size)
{
	void *memory_allocated;

	if ((memory_allocated = realloc(old_addr, size)) == NULL)
		temelia_errno = MEMORY_ALLOCATION;

#ifdef VERBOSE
	LOGGER("memory (%p) = realloc (%p, %d)\n", memory_allocated, old_addr, size);
#endif

	return memory_allocated;
}

void _delete(void *memory_address)
{
	_ASSERT(memory_address, ==, NULL, NULL_POINTER,);

#ifdef VERBOSE
	LOGGER("free (%p)\n", memory_address);
#endif

	free(memory_address);
}

int compare_pointers(void *x, void *y, void *context)
{
	return (int) x - (int) y;
}

int _rand()
{
	return rand();
}

void report_error(CONST char *RESTRICT _format, ...)
{
	va_list args;
	va_start(args, _format);
	vfprintf(stderr, _format, args);
	va_end(args);
}

//#ifdef DLL
//#define RLS_PRINT(__VA_ARGS__) fprintf(stdout, __VA_ARGS__)
//#else
#define RLS_PRINT(fmt, args...) fprintf(stdout, fmt, ##args)
//#endif

//#ifdef DLL
//#ifdef DEBUG
//#define DBG_PRINT(__VA_ARGS__)	RLS_PRINT(" [DBG] " __VA_ARGS__)
//#else
//#define DBG_PRINT(__VA_ARGS__)
//#endif
//#else
#ifdef DEBUG
#define DBG_PRINT(fmt, args...)	RLS_PRINT(" [DBG] " fmt, ##args)
#else
#define DBG_PRINT(fmt, args...)
#endif
//#endif

#define INCONSISTENT_ERROR() \
do\
{\
  	fprintf(stderr, "[%s : %d] INCONSISTENT ERROR!\n", __FILE__, __LINE__);\
    exit(1);\
} while(0)

void _logger_init(void *output_stream)
{
	fprintf(output_stream, "[logger] initializing logger (%p)\n", output_stream);

	fout = output_stream;
}

void _logger_log(CONST char *RESTRICT _format, ...)
{
	va_list args;

	if (fout == NULL)
		return;

	va_start(args, _format);
	fprintf(fout, "[logger] ");
	vfprintf(fout, _format, args);
	va_end(args);
	fflush(fout);
}

void _logger_destroy()
{
	_ASSERT(fout, ==, NULL, NULL_POINTER,);

	fprintf(fout, "[logger] destroying logger\n");
	if (fout == stdout)
		fout = NULL;
	else
		fclose(fout);
}

void _empty_init(void *output_stream)
{
}

void _empty_log(CONST char *RESTRICT _format, ...)
{
}

void _empty_destroy()
{
}

// Declared in binary_tree.c: line 29
extern stack_t iterating_handlers;
extern stack_t compare_stack;

int temelia_inited = 0;

void temelia_init()
{
	/*
	 * Various initializations come here
	 */

	// Already inited?
	if (temelia_inited)
		return;

	if (!iterating_handlers)
		iterating_handlers = stack_new(DEFAULT_SIZE);

	if (!compare_stack)
		compare_stack = stack_new(DEFAULT_SIZE);
	temelia_inited = 1;
}

void temelia_finish()
{
	if (iterating_handlers)
	{
		stack_delete(iterating_handlers);
		iterating_handlers = NULL;
	}

	if (compare_stack)
	{
		stack_delete(compare_stack);
		compare_stack = NULL;
	}
}
